package picobot.map;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.HashMap;

import picobot.interfaces.core.IMap;
import picobot.interfaces.core.IMapBuilder;

/**
 * a class that builds up a map
 */
public class MapBuilder implements IMapBuilder {

	private HashMap<Integer[], Boolean> toBuildMap = new HashMap<Integer[], Boolean>();

	private static char LINE_SEPERATOR = System.getProperty("line.separator")
			.charAt(0);

	/**
	 * returns the number of lines of a String, i.e. the number of times a line
	 * break occurs plus 1
	 * 
	 * @param stringRepresentation
	 *            is the String, the number of lines is to be returned
	 * @return the number of lines of the given String as an integer
	 */
	public int getStringLines(String stringRepresentation) {
		int linesOfString = 1;

		for (int i = 0; i < stringRepresentation.length(); i++) {
			if (stringRepresentation.charAt(i) == LINE_SEPERATOR)
				linesOfString += 1;
		}

		return linesOfString;
	}

	@Override
	public void parseMap(String stringRepresentation) {
		toBuildMap.clear();

		int nol = getStringLines(stringRepresentation);

		int i = 0;

		for (int y = nol - 1; y >= 0; y--) {
			for (int x = 0; x <= stringRepresentation.length(); x++) {
				if (i < stringRepresentation.length()) {
					if (stringRepresentation.charAt(i) == '#') {
						this.placeWall(x, y);
						i += 1;
					} else {
						if (stringRepresentation.charAt(i) == ' ') {
							this.placeFreeCell(x, y);
							i += 1;
						} else {
							if (stringRepresentation.charAt(i) == LINE_SEPERATOR) {
								i += System.getProperty("line.separator")
										.length();
								x += stringRepresentation.length();
							} else {
								i += 1;
							}
						}
					}
				}
			}
		}

	}

	@Override
	public void parseMap(File mapFile) {
		StringBuilder sb = new StringBuilder();

		try {
			BufferedReader br = new BufferedReader(new FileReader(mapFile));
			String content;

			// reads out a line in the code and adds a line break at the end
			while ((content = br.readLine()) != null) {

				sb.append(content + System.getProperty("line.separator"));
			}
			br.close();

		} catch (IOException e) {
			e.printStackTrace();
		}

		// the last line break, the one that is appended to the last line, is
		// deleted
		sb.deleteCharAt(sb.lastIndexOf(System.getProperty("line.separator")));

		this.parseMap(sb.toString());

	}

	@Override
	public void createEmptySquareMap(int size) {
		toBuildMap.clear();

		// the two walls to the right and left
		for (int i = 0; i < size; i++) {
			this.placeWall(0, i);
			this.placeWall(size - 1, i);
		}

		// the empty space in the middle
		for (int i = 1; i < (size - 1); i++) {
			for (int j = 1; j < (size - 1); j++) {
				this.placeFreeCell(j, i);
			}
		}

		// the two walls to the north and south of the empty space,
		// between the walls to the right and left
		for (int i = 1; i < (size - 1); i++) {
			this.placeWall(i, 0);
			this.placeWall(i, size - 1);
		}

	}

	/**
	 * adds a block, that is either a wall or a free cell
	 * 
	 * @param x
	 *            the x coordinate of the block
	 * @param y
	 *            the y coordinate of the block
	 * @param val
	 *            the value of the block type: true for wall, false for free
	 *            cell
	 */
	public void addBlock(int x, int y, boolean val) {
		Integer[] coordinates = new Integer[2];
		coordinates[0] = x;
		coordinates[1] = y;

		toBuildMap.put(coordinates, val);
	}

	@Override
	public void placeWall(int x, int y) {
		addBlock(x, y, true);

	}

	@Override
	public void placeFreeCell(int x, int y) {
		addBlock(x, y, false);

	}

	@Override
	public IMap getCurrentMap() {
		IMap currentMap = new Map(toBuildMap);
		return currentMap;
	}

	@Override
	public void modify(IMap map) {
		this.parseMap(map.toString());
	}

}
